package com.navinfo.platform.trip.common.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.Collection;

import static java.math.BigDecimal.ROUND_HALF_UP;

/**
 * BigDecimal工具类.
 * 注意double转换 BigDecimal时需要先转换成string，防止精度混乱.
 *
 * @author 水哥
 */
public class BigDecimalUtils {
    private static final Logger logger = LoggerFactory.getLogger(BigDecimalUtils.class);
    /**
     * 乘法int*int.
     *
     * @param a int类型数字
     * @param b int类型数字
     * @return BigDecimal
     */
    public static BigDecimal multiply(Integer a, Integer b) {
        return BigDecimal.valueOf(a).multiply(BigDecimal.valueOf(b));
    }

    /**
     * 乘法double*int，四舍五入.
     *
     * @param a     double类型数字
     * @param b     int类型数字
     * @param scale 保留小数点位数精度
     * @return BigDecimal
     */
    public static BigDecimal multiply(Double a, Integer b, int scale) {
        return BigDecimal.valueOf(a).multiply(BigDecimal.valueOf(b)).setScale(scale, ROUND_HALF_UP);
    }

    /**
     * 乘法double*double，四舍五入.
     *
     * @param a     double类型数字
     * @param b     double类型数字
     * @param scale 保留小数点位数精度
     * @return BigDecimal
     */
    public static BigDecimal multiply(Double a, Double b, int scale) {
        return BigDecimal.valueOf(a).multiply(BigDecimal.valueOf(b)).setScale(scale, ROUND_HALF_UP);
    }

    /**
     * 乘法BigDecimal*int，四舍五入.
     *
     * @param a     BigDecimal类型数字
     * @param b     int类型数字
     * @param scale 保留小数点位数精度
     * @return BigDecimal
     */
    public static BigDecimal multiply(BigDecimal a, Integer b, int scale) {
        return a.multiply(BigDecimal.valueOf(b)).setScale(scale, ROUND_HALF_UP);
    }

    /**
     * 除法long/int，四舍五入.
     * @param a     Long类型数字
     * @param b     int类型数字
     * @param scale 保留小数点位数精度
     * @return BigDecimal
     */
    public static BigDecimal divide(Long a, Integer b, int scale) {
        if(null==a || 0==a || null==b || 0==b){
            return BigDecimal.ZERO;
        }
        return BigDecimal.valueOf(a).divide(BigDecimal.valueOf(b), scale, ROUND_HALF_UP);
    }

    /**
     * 除法Double/BigDecimal，四舍五入.
     *
     * @param a     Double类型数字
     * @param b     BigDecimal类型数字
     * @param scale 保留小数点位数精度
     * @return BigDecimal
     */
    public static BigDecimal divide(Double a, BigDecimal b, int scale) {
        if(null==a || 0.0==a || null==b || BigDecimal.ZERO.equals(b)){
            return BigDecimal.ZERO;
        }
        return BigDecimal.valueOf(a).divide(b, scale, ROUND_HALF_UP);
    }

    /**
     * 除法Double/BigDecimal，四舍五入.
     *
     * @param a     Double类型数字
     * @param b     Double类型数字
     * @param scale 保留小数点位数精度
     * @return BigDecimal
     */
    public static BigDecimal divide(Double a, Double b, int scale) {
        if(null==a || 0.0==a || null==b || 0.0==b){
            return BigDecimal.ZERO;
        }
        return BigDecimal.valueOf(a).divide(BigDecimal.valueOf(b), scale, ROUND_HALF_UP);
    }
    /**
     * 除法Integer/Integer，四舍五入.
     *
     * @param a     Integer类型数字
     * @param b     Integer类型数字
     * @param scale 保留小数点位数精度
     * @return BigDecimal
     */
    public static BigDecimal divide(Integer a, Integer b, int scale) {
        if(null==a || 0==a || null==b || 0==b){
            return BigDecimal.ZERO;
        }
        return BigDecimal.valueOf(a).divide(BigDecimal.valueOf(b), scale, ROUND_HALF_UP);
    }

    /**
     * 除法Integer/Long，四舍五入.
     *
     * @param a     Integer类型数字
     * @param b     Long类型数字
     * @param scale 保留小数点位数精度
     * @return BigDecimal
     */
    public static BigDecimal divide(Integer a, Long b, int scale) {
        if(null==a || 0==a || null==b || 0==b){
            return BigDecimal.ZERO;
        }
        return BigDecimal.valueOf(a).divide(BigDecimal.valueOf(b), scale, ROUND_HALF_UP);
    }

    /**
     * 除法Double/Long，四舍五入.
     *
     * @param a     Double类型数字
     * @param b     Long类型数字
     * @param scale 保留小数点位数精度
     * @return BigDecimal
     */
    public static BigDecimal divide(Double a, Long b, int scale) {
        if(null==a || 0.0==a || null==b || 0==b){
            return BigDecimal.ZERO;
        }
        return BigDecimal.valueOf(a).divide(BigDecimal.valueOf(b), scale, ROUND_HALF_UP);
    }

    /**
     * 除法Double/Integer，四舍五入.
     *
     * @param a     Double类型数字
     * @param b     Integer类型数字
     * @param scale 保留小数点位数精度
     * @return BigDecimal
     */
    public static BigDecimal divide(Double a, Integer b, int scale) {
        if(null==a || 0.0==a || null==b || 0==b){
            return BigDecimal.ZERO;
        }
        return BigDecimal.valueOf(a).divide(BigDecimal.valueOf(b), scale, ROUND_HALF_UP);
    }

    /**
     * 除法BigDecimal/Integer，四舍五入.
     *
     * @param a     BigDecimal类型数字
     * @param b     Integer类型数字
     * @param scale 保留小数点位数精度
     * @return BigDecimal
     */
    public static BigDecimal divide(BigDecimal a, Integer b, int scale) {
        if(null==a || BigDecimal.ZERO.equals(a) || null==b || 0==b){
            return BigDecimal.ZERO;
        }
        return a.divide(BigDecimal.valueOf(b), scale, ROUND_HALF_UP);
    }

    /**
     * 计算标准差.
     * @param collection double集合
     * @return double 标准差
     */
    public static double standardDeviation(Number[] collection) {
        if (null == collection) {
            return 0;
        }
        double sum = 0;
        int length = collection.length;
        double avg = average(collection);
        for (Number i : collection) {
            if(null == i){
                length -= 1;
            }else{
                double j =  i.doubleValue();
                sum += (j-avg) * (j-avg);
            }
        }

        if (length <= 0) {
            return 0;
        }

        return BigDecimal.valueOf(Math.sqrt(sum / length)).setScale(2,ROUND_HALF_UP ).doubleValue();
    }

    /**
     * 计算平均值<br/>
     * 数组中为null的元素不进行统计
     * @param collection 待计算集合
     * @return  平均值
     */
    public static double average(Number[] collection) {
        if (null == collection) {
            return 0;
        }
        double sum = 0;
        int length = collection.length;
        for (Number i : collection) {
            if(null == i){
                length -= 1;
            }else{
                sum += i.doubleValue();
            }
        }

        if (length <= 0) {
            return 0;
        }

        return divide(sum, length, 2).doubleValue();
    }


}
